package libra;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;

/**
 * 【 该BlockExceptionHandler只能处理自身应用所触发的Sentinel异常，但是解决不了通过RestTemplate调用Provider，Provider所触发的Sentinel异常 】
 * 自定义全局BlockException的统一异常处理器，参照贴：https://blog.csdn.net/m0_37965811/article/details/122810374?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.pc_relevant_aa&utm_relevant_index=9
 * 	每当触发Sentinel防护规则，实际上都会在系统内部产生BlockException异常实例，然后再基于默认的方式进行异常处理。
 * 	默认情况Sentinel在发生blockException时默认返回仅仅是一句Blocked by Sentinel (flow limiting)，
 * 	Sentinel内部提供了BlockExceptionHandler接口，开发者可以直接依据此接口进行自定义异常数据的处理
 * @author libra
 */
@Component
public class CoustomBlockExHandler implements BlockExceptionHandler {
	/**
     * 异常处理
     * @param req  请求
     * @param resp 响应
     * @param e BlockException异常接口，包含Sentinel的五个异常
     *            FlowException(限流异常)、DegradeException(降级异常)、ParamFlowException(参数限流异常)、
     *            AuthorityException(授权异常)、SystemBlockException(系统负载异常)、
	 */
	@Override
	public void handle(HttpServletRequest req, HttpServletResponse resp, BlockException e) throws Exception {
		//getRule()返回资源、规则的详细信息
		System.out.println( e.getRule() );
		String info = "";
		if ( e instanceof FlowException ) {
			 info = String.format("流控异常，请求【%s】，异常【%s】", req.getRequestURL(), e.getClass().getSimpleName() );
		} else if ( e instanceof DegradeException ) {
			 info = String.format("熔断异常，请求【%s】，异常【%s】", req.getRequestURL(), e.getClass().getSimpleName() );
		} else if ( e instanceof ParamFlowException ) {
			 info = String.format("热点key异常，请求【%s】，异常【%s】", req.getRequestURL(), e.getClass().getSimpleName() );
		} else if ( e instanceof SystemBlockException ) {
			 info = String.format("系统保护异常，请求【%s】，异常【%s】", req.getRequestURL(), e.getClass().getSimpleName() );
		} else if ( e instanceof AuthorityException ) {
			 info = String.format("授权异常，请求【%s】，异常【%s】", req.getRequestURL(), e.getClass().getSimpleName() );
		} else {
			// 因为该类只处理Sentinel引发的流控、降级异常，所以基本不会进入到本分支中
			info = String.format("执行异常，请求【%s】，异常【%s】", req.getRequestURL(), e.getClass().getSimpleName() );
		}
		System.err.println( info );
		resp.setStatus(439);
		resp.setCharacterEncoding("utf-8");
		resp.setHeader("Content-Type", "application/json;charset=utf-8");
		resp.setContentType("application/json;charset=utf-8");
		resp.getWriter().write( String.format("{'info':'%s'}", info) );
	}
}
